const app = getApp()
const {
  $Message
} = require('../../dist/base/index');
let this_
/**
 * 事件
 */
const myEvent = {}
/**
 * 发送进度
 */
let send_offset = 0
/**
 * 文件最大尺寸
 */
const FILE_MAX_SIZE = 1024 * 512
/**
 * 协议包头
 */
const BLE_CMD_PACK_HEAD = 0x5772
/**
 * 一次最大发送数据量
 */
const BLE_PACK_MAX_LEN = 128
/**
 * 快速模式
 */
var speed_mode_fig = false
var speed_mode_sw = false
/**
 * 指令码
 */
const BLECMD = {
  BLE_CMD_SEND_FIRMWARE_DATA: 0x01,
  BLE_CMD_FIRWART_INFO: 0x02,
  BLE_CMD_FIRWART_SUM_RET: 0x03
}
/**
 * 蓝牙总开关标记
 */
let switchFig = false
/**
 * 已连接的蓝牙设备信息
 */
let cho_device_uuid = ''
let cho_server_uuid = ''
/**
 * 搜索到的蓝牙设备信息
 */
let lis_device = []
let lis_server = []
let lis_cha = []
/**
 * 选择要操作的蓝牙设备读写uuid
 */
let cho_cha1_uuid = ''
let cho_cha2_uuid = ''
/**
 * 进度条
 */
let send_progress = 0
/**
 * 记录是否已连接蓝牙与文件选择
 */
let ble_state_change = false
let get_file_state = false
/**
 * 文件数据缓冲
 */
let file_array
/**
 * 
 * 文件长度 
 */
let file_size
/**
 * 文件校验信息
 */
let file_md5_str = '';
/**
 * 接收事件
 */
let rec_evetn
/**
 * 发送状态
 */
let send_state = false

function str2ab(str) {
  var buf = new ArrayBuffer(str.length * 2);
  var bufView = new Uint8Array(buf);
  for (var i = 0, strLen = str.length; i < strLen; i++) {
    bufView[i] = str.charCodeAt(i);
  }
  return buf;
}

function ab2hex(buffer) {
  var hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function (bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join(' ');
}

function buf2hex(buffer) {
  return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(' ');
}

function Str2Bytes(str) {
  var pos = 0;
  var reg = new RegExp(" ", "g");
  var str2 = str.replace(reg, "");
  var len = str2.length;

  if (len % 2 != 0)
    return null;

  len /= 2;
  var buf = new ArrayBuffer(len);
  var bufView = new Uint8Array(buf);
  for (var i = 0; i < len; i++) {
    var s = str2.substr(pos, 2);
    var v = parseInt(s, 16);
    bufView[i] = v;
    pos += 2;
  }
  return buf;
}

function send(value, offset) {
  const buffer = value.slice(offset, offset + 20);

  if (buffer.byteLength == 0)
    return

  wx.writeBLECharacteristicValue({
    characteristicId: cho_cha1_uuid,
    deviceId: cho_device_uuid,
    serviceId: cho_server_uuid,
    value: buffer,
    success: () => {
      send(value, offset + 20);
    },
    fail: (err) => {
      console.log(err)
      wx.showToast({
        title: '写入失败',
      })
    }
  });
}

function sendBleData(value) {
  /**
   * 快速模式
   */
  if (speed_mode_fig == true) {
    wx.writeBLECharacteristicValue({
      characteristicId: cho_cha1_uuid,
      deviceId: cho_device_uuid,
      serviceId: cho_server_uuid,
      value: value,
      success: (res) => {
        console.log(res)
      },
      fail: (err) => {
        console.log(err)
        wx.showToast({
          title: '写入失败',
        })
      }
    })
  } else {
    /**
     * 分包模式
     */
    send(value, 0);
  }
}

/**
 * 发送固件信息
 */
function sned_firmwart_info(len, file_md5, limit) {
  console.log("发送固件信息")
  console.log("固件长度", len)
  console.log("固件校MD5: ", file_md5)
  if (limit)
    console.log("烧录次数限制：", limit)
  else
    console.log("不限烧录次数")

  var arraybuffer = new ArrayBuffer(5 + 24);
  var obj = new DataView(arraybuffer);

  obj.setUint8(0, (BLE_CMD_PACK_HEAD & 0xFF00) >> 8)
  obj.setUint8(1, (BLE_CMD_PACK_HEAD & 0x00FF) >> 0)
  obj.setUint8(2, BLECMD.BLE_CMD_FIRWART_INFO)
  obj.setUint8(3, 24)

  //len
  obj.setUint8(4, (len >> 24) & 0xFF)
  obj.setUint8(5, (len >> 16) & 0xFF)
  obj.setUint8(6, (len >> 8) & 0xFF)
  obj.setUint8(7, (len >> 0) & 0xFF)
  //md5
  for (let i = 0; i < 16; i++)
    obj.setUint8(8 + i, (parseInt("0x" + file_md5.substring(i * 2 + 0, i * 2 + 1)) * 16) + parseInt("0x" + file_md5.substring(i * 2 + 1, i * 2 + 2)))

  //limit
  if (limit) {
    let limit_value = parseInt(limit)
    obj.setUint8(24, (limit_value >> 24) & 0xFF)
    obj.setUint8(25, (limit_value >> 16) & 0xFF)
    obj.setUint8(26, (limit_value >> 8) & 0xFF)
    obj.setUint8(27, (limit_value >> 0) & 0xFF)
  } else {
    obj.setUint8(24, 0xFF)
    obj.setUint8(25, 0xFF)
    obj.setUint8(26, 0xFF)
    obj.setUint8(27, 0xFF)
  }

  let sum = 0
  for (let i = 0; i < (obj.getUint8(3) + 4); i++)
    sum += obj.getUint8(i)

  obj.setUint8(obj.getUint8(3) + 4, sum & 0xFF)

  sendBleData(arraybuffer)
}

/**
 * 发送固件数据
 */
function sned_firmwart_data(address, value, len) {
  console.log("发送固件数据指令")
  console.log("发送的数据长度：", len)

  var arraybuffer = new ArrayBuffer(9 + len);
  var obj = new DataView(arraybuffer);

  obj.setUint8(0, (BLE_CMD_PACK_HEAD & 0xFF00) >> 8)
  obj.setUint8(1, (BLE_CMD_PACK_HEAD & 0x00FF) >> 0)
  obj.setUint8(2, BLECMD.BLE_CMD_SEND_FIRMWARE_DATA)
  obj.setUint8(3, len + 4)

  obj.setUint8(4, (address >> 24) & 0xFF)
  obj.setUint8(5, (address >> 16) & 0xFF)
  obj.setUint8(6, (address >> 8) & 0xFF)
  obj.setUint8(7, (address >> 0) & 0xFF)

  for (let i = 0; i < len; i++)
    obj.setUint8(8 + i, value[i]);

  let sum = 0
  for (let i = 0; i < (obj.getUint8(3) + 4); i++)
    sum += obj.getUint8(i)

  obj.setUint8(obj.getUint8(3) + 4, sum & 0xFF)

  sendBleData(arraybuffer)
}

/**
 * 发送请求校验固件
 */
function sned_firmwart_sum_info() {
  console.log("发送请求校验固件")

  var arraybuffer = new ArrayBuffer(5 + 6);
  var obj = new DataView(arraybuffer);

  obj.setUint8(0, (BLE_CMD_PACK_HEAD & 0xFF00) >> 8)
  obj.setUint8(1, (BLE_CMD_PACK_HEAD & 0x00FF) >> 0)
  obj.setUint8(2, BLECMD.BLE_CMD_FIRWART_SUM_RET)
  obj.setUint8(3, 0)

  let sum = 0
  for (let i = 0; i < (obj.getUint8(3) + 4); i++)
    sum += obj.getUint8(i)

  obj.setUint8(obj.getUint8(3) + 4, sum & 0xFF)

  sendBleData(arraybuffer)
}

function parsingData(e) {
  var obj = new DataView(e);

  if (obj.getUint8(0) == ((BLE_CMD_PACK_HEAD & 0xFF00) >> 8) && obj.getUint8(1) == ((BLE_CMD_PACK_HEAD & 0x00FF) >> 0)) {
    let sum = 0
    for (let i = 0; i < (obj.getUint8(3) + 4); i++)
      sum += obj.getUint8(i)

    if ((sum & 0xFF) == obj.getUint8(obj.getUint8(3) + 4)) {
      console.log("收到有效数据")
      switch (obj.getUint8(2)) {
        case BLECMD.BLE_CMD_SEND_FIRMWARE_DATA:
        case BLECMD.BLE_CMD_FIRWART_INFO:
          if (obj.getUint8(4) == 0) {
            send_state = false;
            wx.showToast({
              title: 'tool：固件写入失败',
            })
            this_.setData({
              progress_sw: false
            })
            return;
          }

          myEvent['event_send'](0)
          break;
        case BLECMD.BLE_CMD_FIRWART_SUM_RET:
          if (obj.getUint8(4) == 1) {
            let get_md5_str = ''
            for (let i = 0; i < 16; i++)
              get_md5_str = get_md5_str + (obj.getUint8(5 + i).toString(16).toUpperCase())

            DoneMusic('music/Alarm03.wav')
            $Message({
              content: 'tool：固件校验通过，MD5：' + get_md5_str
            });

            this_.setData({
              status_bar: "目标设备片上固件有效"
            })
          } else {
            DoneMusic('music/Windows Exclamation.wav')
            $Message({
              content: 'tool：固件校验失败'
            });
            this_.setData({
              status_bar: "目标设备片上固件无效"
            })
          }
          break;
      }
    }
  }
}

function DoneMusic(local) {
  const innerAudioContext = wx.createInnerAudioContext()
  innerAudioContext.autoplay = true
  innerAudioContext.src = local
  innerAudioContext.onPlay(() => {
    /**开始播放是触发 */
    console.log('Start playback')
  })
  innerAudioContext.onError((res) => {
    /**播放是有错误时触发 */
    console.log(res.errMsg)
    console.log(res.errCode)
  })
}

Page({
  data: {
    file_name_itile: '未选择固件',
    file_name_label: '限制最大 512 kbyte',
    openBluetooth_word: "打开蓝牙",
    bt_list_itile: '未打开蓝牙',
    bt_list_label: '未选择设备',
    bt_ico: 'fullscreen',
    percent_value: send_progress,
    progress_sw: false,
    sendFile_sw: false,
    status_bar: "欢迎使用，请点击\"打开蓝牙\"按钮进行配置"
  },
  onLoad: function () {
    this_ = this
    DoneMusic('music/Windows Logon.wav')
    /**
     * start
     */
    wx.setKeepScreenOn({
      keepScreenOn: true
    })
    /**
     * system info
     */
    wx.getSystemInfo({
      success(res) {
        console.log(res.model)
        console.log(res.pixelRatio)
        console.log(res.windowWidth)
        console.log(res.windowHeight)
        console.log(res.language)
        console.log(res.version)
        console.log(res.platform)

        // if (res.platform == 'ios') {
        //   speed_mode_fig = true
        //   speed_mode_sw = false
        //   this_.setData({
        //     speed_switch: speed_mode_fig,
        //     speed_switch_onChange_sw: speed_mode_sw,
        //     speed_switch_label: 'IOS 可以尝试使用快速模式'
        //   })
        // } else {
        //   speed_mode_fig = false
        //   speed_mode_sw = false
        //   this_.setData({
        //     speed_switch: speed_mode_fig,
        //     speed_switch_onChange_sw: speed_mode_sw,
        //     speed_switch_label: '该平台使用快速模式可能存在问题'
        //   })
        // }

        speed_mode_fig = true
        speed_mode_sw = true
        this_.setData({
          speed_switch: speed_mode_fig,
          speed_switch_onChange_sw: false,
          speed_switch_label: '强制打开快速模式，仅IOS平台可用'
        })
      }
    })

    this.onBluetoothDeviceFound()
  },
  turn_off_ble: function (e) {
    console.log("function: turn_off_ble")
    switchFig = false
    wx.closeBluetoothAdapter()

    lis_device = []
    lis_server = []
    lis_cha = []
    ble_state_change = false
    send_state = false

    this.setData({
      status_bar: "欢迎使用，请点击\"打开蓝牙\"按钮进行配置",
      deviceListSwitch: false,
      openBluetooth_word: "打开蓝牙",
      bt_list_itile: '未打开蓝牙',
      bt_list_label: '未选择设备',
      bt_ico: 'fullscreen',
      progress_sw: false,
      sendFile_sw: false,
      chack_firwart_bt_sw: false
    })
  },
  openBluetooth: function (e) {
    console.log("function: openBluetooth")

    wx.vibrateShort()
    let services_array = []
    services_array[0] = "0000ABF0-0000-1000-8000-00805F9B34FB"
    if (switchFig == false) {
      wx.openBluetoothAdapter({
        success: (res) => {
          console.log(res)
          wx.startBluetoothDevicesDiscovery({
            services: services_array,
            success: (res) => {
              console.log(res)

              wx.showToast({
                title: '打开成功',
              })

              switchFig = true
              this.setData({
                openBluetooth_word: "关闭蓝牙",
                bt_list_itile: '已打开蓝牙'
              })
            },
            fail: (err) => {
              console.log(err)

              wx.showToast({
                title: '打开失败',
              })
            }
          })
        },
        fail: (err) => {
          console.log(err)

          wx.showToast({
            title: '请打开系统蓝牙',
          })
        }
      })
    } else {
      this.turn_off_ble()
    }
  },
  onBluetoothDeviceFound() {
    wx.onBluetoothDeviceFound(() => {
      wx.getBluetoothDevices({
        success: (res) => {
          console.log(res)
          lis_device = []

          if (res.devices.length != 0) {
            for (var i = 0; i < res.devices.length; i++) {
              if (res.devices[i].name != "ESP_SPP_SERVER")
                continue;

              lis_device.push({
                title: res.devices[i].name,
                label: res.devices[i].deviceId,
                rssi: '信号强度：' + res.devices[i].RSSI + 'dbm',
                _rssi: res.devices[i].RSSI
              })
            }

            lis_device.sort((a, b) => {
              return b._rssi - a._rssi
            })

            console.log(lis_device)
            this.setData({
              deviceListSwitch: true,
              device_list: lis_device,
              status_bar: "请选择设备"
            })
          } else {
            this.setData({
              deviceListSwitch: false
            })
          }
        },
        fail: (err) => {
          console.log(err)
        }
      })
    })
  },
  async createBLEConnection(e) {
    console.log("function: createBLEConnection", e.currentTarget.dataset.index)
    console.log("connect device id: ", lis_device[e.currentTarget.dataset.index].label)
    console.log("connect device name: ", lis_device[e.currentTarget.dataset.index].title)

    if (switchFig != true) {
      wx.showToast({
        title: '请开启蓝牙',
      })
      return
    }

    if (cho_device_uuid != '') {
      try {
        let cl = await wx.closeBLEConnection({
          deviceId: cho_device_uuid,
        })
        console.log(cl)
      } catch (e) {
        console.log(e)
      }
    }

    wx.showToast({
      title: '正在连接',
    })

    cho_device_uuid = lis_device[e.currentTarget.dataset.index].label
    wx.createBLEConnection({
      deviceId: cho_device_uuid,
      timeout: 6000,
      success: (res) => {
        console.log(res)
        ble_state_change = true
        wx.showToast({
          title: '连接成功',
        })

        wx.onBLEConnectionStateChange((res) => {
          console.log(res)
          console.log('设备连接状态：' + res.connected)
          if (res.connected == false) {
            ble_state_change = false

            this.setData({
              sendFile_sw: false
            })
            DoneMusic("music/Windows Hardware Remove.wav")
            wx.showToast({
              title: '设备断开连接',
            })
            this.turn_off_ble();
          } else
            ble_state_change = true
        })

        wx.getBLEDeviceServices({
          deviceId: cho_device_uuid,
          success: (res) => {
            console.log(res)

            lis_server = []
            for (var i = 0; i < res.services.length; i++) {
              lis_server.push({
                title: res.services[i].uuid,
                label: "server"
              })

              if (res.services[i].uuid == "0000ABF0-0000-1000-8000-00805F9B34FB") {
                console.log("找到服务")
                cho_server_uuid = res.services[i].uuid

                wx.getBLEDeviceCharacteristics({
                  deviceId: cho_device_uuid,
                  serviceId: cho_server_uuid,
                  success: (res) => {
                    console.log(res)

                    lis_cha = []
                    let get_cha = 0
                    for (var i = 0; i < res.characteristics.length; i++) {
                      lis_cha.push({
                        title: res.characteristics[i].uuid,
                        label: "uuid",
                        properties: {
                          indicate: res.characteristics[i].properties.indicate,
                          notify: res.characteristics[i].properties.notify,
                          read: res.characteristics[i].properties.read,
                          write: res.characteristics[i].properties.write
                        }
                      })

                      if (res.characteristics[i].uuid == "0000ABF1-0000-1000-8000-00805F9B34FB") {
                        if (res.characteristics[i].properties.write == true) {
                          cho_cha1_uuid = res.characteristics[i].uuid
                          console.log("找到写入数据特征")
                          get_cha |= 0x01
                        }
                      }

                      if (res.characteristics[i].uuid == "0000ABF2-0000-1000-8000-00805F9B34FB") {
                        if (res.characteristics[i].properties.notify == true) {
                          cho_cha2_uuid = res.characteristics[i].uuid
                          console.log("找到监听数据特征")
                          get_cha |= 0x02

                          /**
                           * 监听特诊
                           */
                          wx.notifyBLECharacteristicValueChange({
                            characteristicId: cho_cha2_uuid,
                            deviceId: cho_device_uuid,
                            serviceId: cho_server_uuid,
                            state: true,
                            success: (res) => {
                              console.log(res)

                              wx.onBLECharacteristicValueChange(
                                (res) => {
                                  console.log(res)
                                  console.log(ab2hex(res.value))
                                  parsingData(res.value)
                                }
                              )
                            }
                          })
                        }
                      }
                    }

                    if (get_cha != 0x03) {
                      console.log("设备特征不符合规则")
                      this.turn_off_ble()
                      wx.showToast({
                        title: '设备特征不符合规则',
                      })
                    } else {
                      DoneMusic('music/Windows Hardware Insert.wav')
                      console.log("设备特征符合规则")
                      wx.showToast({
                        title: '设备特征符合规则',
                      })

                      if (get_file_state == true) {
                        this.setData({
                          sendFile_sw: true,
                          status_bar: "选择的设备有效，点击发送固件",
                          chack_firwart_bt_sw: true
                        })
                      } else {
                        this.setData({
                          status_bar: "请选择固件",
                          chack_firwart_bt_sw: true
                        })
                      }
                    }
                  }
                })
              }
            }

            this.setData({
              bt_list_label: '已连接设备：' + lis_device[e.currentTarget.dataset.index].title,
              deviceListSwitch: false,
              bt_ico: 'narrow'
            })
          }
        })
      },
      fail: (err) => {
        console.log(err)
        wx.showToast({
          title: '连接失败',
        })
      }
    })
    wx.stopBluetoothDevicesDiscovery()
  },
  chooseMessageFile: function (e) {
    console.log("function: chooseMessageFile")

    if (send_state == true) {
      wx.showToast({
        title: '正在发送固件',
      })
      return
    }

    let this_ = this
    let file_arr = [1]
    file_arr[0] = 'bin'

    let file_info_str = ''
    let info = []
    wx.chooseMessageFile({
      count: 1,
      type: 'file',
      extension: file_arr,
      success: (res) => {
        console.log("选择文件成功")
        console.log(res)

        file_size = res.tempFiles[0].size
        if (file_size > FILE_MAX_SIZE) {
          console.log('文件超出大小：', file_size)
          return
        }

        get_file_state = true
        info.push({})

        this.setData({
          file_info_switch: true,
          file_name_itile: res.tempFiles[0].name,
          info_list: info,
          file_name_label: (res.tempFiles[0].size / 1024).toFixed(2) + ' (kbyte), ' + res.tempFiles[0].size + ' (byte)'
        })

        if (ble_state_change == true) {
          this.setData({
            sendFile_sw: true,
            status_bar: "点击发送固件按钮"
          })
        } else {
          this.setData({
            status_bar: "下一步连接蓝牙"
          })
        }

        const fs = wx.getFileSystemManager()
        const ab = new ArrayBuffer(FILE_MAX_SIZE)

        fs.open({
          filePath: res.tempFiles[0].path,
          flag: 'r',
          success(res) {
            fs.read({
              fd: res.fd,
              arrayBuffer: ab,
              length: file_size,
              success(res) {
                console.log('读取结果：', res)
                console.log(res.arrayBuffer)

                file_array = new Uint8Array(res.arrayBuffer);
                console.log("输出固件数据")
                console.log(file_array)

                let md5_ret = []
                for (let i = 0; i < file_size; i++)
                  md5_ret[i] = file_array[i]

                /**
                 * 计算文件md5值
                 */
                var utilMd5 = require('../utils/md5.js');
                file_md5_str = utilMd5.hexMD5(md5_ret);
                info[0].sum = file_md5_str.toUpperCase()
                this_.setData({
                  file_info_switch: true,
                  info_list: info
                })
              }
            })
          }
        })
      },
      fail: (res) => {
        console.log("选择文件失败")
      }
    })
  },
  /**
   * 
   * 发送固件
   */
  sendFile(e) {
    console.log('发送固件')

    if (send_state == true) {
      wx.showToast({
        title: '已正在发送固件',
      })
      return
    }
    /**
     * 重置发送进度
     */
    send_offset = 0;

    /**
     * 记录发送状态
     */
    send_state = true
    /**
     * 展示进度条
     */
    this.setData({
      progress_sw: true,
      percent_value: 0,
      status_bar: "请耐心等待固件发送"
    })

    DoneMusic('music/Windows Information Bar.wav')
    wx.vibrateShort()
    /**
     * 准备发送流程事件
     */
    myEvent['event_send'] = (res) => {
      let now_send_len

      if (file_size == send_offset) {
        console.log("[自定义事件][event_send]")
        console.log("事件完毕")
        send_state = false

        DoneMusic('music/Windows Proximity Notification.wav')
        wx.vibrateLong()
        wx.showToast({
          title: '固件发送完毕',
          duration: 2000
        })

        this.setData({
          status_bar: "固件发送完毕，点击\"校验固件\"检查固件完整"
        })
        return
      }

      if ((file_size - send_offset) > BLE_PACK_MAX_LEN) {
        now_send_len = BLE_PACK_MAX_LEN
      } else {
        now_send_len = file_size - send_offset
      }

      let file_array2 = file_array.slice(send_offset, send_offset + now_send_len);
      sned_firmwart_data(send_offset, file_array2, now_send_len);
      console.log("[自定义事件][event_send]")
      console.log("send_offset:", send_offset, '(', send_offset / 1024, ')')
      console.log("now_send_len:", now_send_len)

      send_offset += now_send_len

      this.setData({
        percent_value: ((send_offset / file_size) * 100).toFixed(1)
      })
    }

    /**
     * 发送固件信息
     */
    sned_firmwart_info(file_size, file_md5_str, this.limit_input);
  },
  /**
   * 快速模式按钮
   */
  speed_switch_onChange(e) {
    console.log(e)

    if (speed_mode_sw == true)
      return

    if (send_state == true) {
      wx.showToast({
        title: '正在发送固件',
      })
      return
    }
    wx.vibrateShort()
    speed_mode_fig = !speed_mode_fig
    this.setData({
      speed_switch: speed_mode_fig
    })
  },
  /**
   * 校验固件
   */
  chack_firwart_bt() {
    if (send_state == true) {
      wx.showToast({
        title: '正在发送固件',
      })
      return
    }

    if (switchFig == false) {
      wx.showToast({
        title: '未打开蓝牙',
      })
      return
    }

    if (ble_state_change == false) {
      wx.showToast({
        title: '未连接设备',
      })
      return
    }

    wx.vibrateShort()
    /**
     * 请求校验固件
     */
    sned_firmwart_sum_info()
  }
})